home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
CUGUK
/
GAMES
/
C059B.ZIP
/
SRC3.ZIP
/
MUSIC.C
< prev
Wrap
C/C++ Source or Header
|
1990-07-18
|
12KB
|
456 lines
/* SCCS Id: @(#)music.c 3.0 88/10/22
/* Copyright (c) 1989 by Jean-Christophe Collet */
/* NetHack may be freely redistributed. See license for details. */
/*
* This file contains the different functions designed to manipulate the
* musical instruments and their various effects.
*
* Actually the list of instruments / effects is :
*
* Flute may calm snakes if player has enough dexterity
* Magic flute may put monsters to sleep: area of effect depends
* on player level.
* Horn Will awaken monsters: area of effect depends on player
* level. May also scare monsters.
* Fire horn Acts like a wand of fire.
* Frost horn Acts like a wand of cold.
* Bugle Will awaken soldiers (if any): area of effect depends
* on player level.
* Harp May calm nymph if player has enough dexterity.
* Magic harp Charm monsters: area of effect depends on player
* level.
* Drum Will awaken monsters like the horn.
* Drum of earthquake Will initiate an earthquake whose intensity depends
* on player level. That is, it creates ramdom pits
* called here chasms.
*/
#include "hack.h"
#ifdef MUSIC
#include <ctype.h>
static void FDECL(awaken_monsters,(int));
static void FDECL(put_monsters_to_sleep,(int));
static void FDECL(charm_snakes,(int));
static void FDECL(calm_nymphs,(int));
static void NDECL(awaken_soldiers);
static void FDECL(charm_monsters,(int));
static void FDECL(do_earthquake,(int));
static int FDECL(do_improvisation,(struct obj *));
/*
* Wake every monster in range...
*/
static void
awaken_monsters(distance)
int distance;
{
register struct monst *mtmp = fmon;
while(mtmp) {
if (dist(mtmp->mx, mtmp->my) < distance/3) {
/* May scare some monsters */
if (!resist(mtmp, SCROLL_SYM, 0, NOTELL))
mtmp->mflee = 1;
} else if (dist(mtmp->mx, mtmp->my) < distance) {
mtmp->msleep = 0;
mtmp->mcanmove = 1;
mtmp->mfrozen = 0;
}
mtmp = mtmp->nmon;
}
}
/*
* Make monsters fall asleep. Note that they may resist the spell.
*/
static void
put_monsters_to_sleep(distance)
int distance;
{
register struct monst *mtmp = fmon;
while(mtmp) {
if (dist(mtmp->mx, mtmp->my) < distance)
if(mtmp->mcanmove && !resist(mtmp, WAND_SYM, 0, NOTELL))
mtmp->mcanmove = mtmp->mfrozen = 0;
mtmp = mtmp->nmon;
}
}
/*
* Charm snakes in range. Note that the snakes are NOT tamed.
*/
static void
charm_snakes(distance)
int distance;
{
register struct monst *mtmp = fmon;
while (mtmp) {
if (mtmp->data->mlet == S_SNAKE && dist(mtmp->mx, mtmp->my) < distance) {
mtmp->mpeaceful = 1;
if (cansee(mtmp->mx, mtmp->my))
pline("%s freezes and sways with the music, then seems quieter.",defmonnam(mtmp));
}
mtmp = mtmp->nmon;
}
}
/*
* Calm nymphs in range.
*/
static void
calm_nymphs(distance)
int distance;
{
register struct monst *mtmp = fmon;
while (mtmp) {
if (mtmp->data->mlet == S_NYMPH && dist(mtmp->mx, mtmp->my) < distance) {
mtmp->mpeaceful = 1;
if (cansee(mtmp->mx, mtmp->my))
pline("%s listens cheerfully to the music, then seems quieter.",defmonnam(mtmp));
}
mtmp = mtmp->nmon;
}
}
/* Awake only soldiers of the level. */
static void
awaken_soldiers() {
#ifdef ARMY
#define IS_SOLDIER(dat) ((int)((dat) - mons) >= PM_UNARMORED_SOLDIER && \
(int) ((dat) - mons) <= PM_CAPTAIN)
register struct monst *mtmp = fmon;
while(mtmp) {
if (IS_SOLDIER(mtmp->data)) {
mtmp->mpeaceful = mtmp->msleep = 0;
mtmp->mcanmove = 1;
}
mtmp = mtmp->nmon;
}
#endif /* ARMY /**/
}
/* Charm monsters in range. Note that they may resist the spell. */
static void
charm_monsters(distance)
int distance;
{
register struct monst *mtmp = fmon, *mtmp2;
while(mtmp) {
mtmp2 = mtmp->nmon;
if(dist(mtmp->mx, mtmp->my) <= distance)
if(!resist(mtmp, SCROLL_SYM, 0, NOTELL))
(void) tamedog(mtmp, (struct obj *) 0);
mtmp = mtmp2;
}
}
/* Generate earthquake :-) of desired force.
* That is: create random chasms (pits).
*/
static void
do_earthquake(force)
int force;
{
register int x,y;
struct monst *mtmp;
struct trap *chasm;
int start_x, start_y, end_x, end_y;
start_x = u.ux - (force * 2);
start_y = u.uy - (force * 2);
end_x = u.ux + (force * 2);
end_y = u.uy + (force * 2);
if (start_x < 1) start_x = 1;
if (start_y < 1) start_y = 1;
if (end_x >= COLNO) end_x = COLNO - 1;
if (end_y >= ROWNO) end_y = ROWNO - 1;
for (x=start_x; x<=end_x; x++)
for (y=start_y; y<=end_y; y++)
if (!rn2(14 - force)) {
switch (levl[x][y].typ) {
#ifdef FOUNTAINS
case FOUNTAIN : /* Make the fountain disappear */
if (cansee(x,y))
pline("The fountain falls into a chasm.");
goto do_pit;
#endif
#ifdef SINKS
case SINK :
if (cansee(x,y))
pline("The kitchen sink falls into a chasm.");
goto do_pit;
#endif
#ifdef ALTARS
case ALTAR :
if (cansee(x,y))
pline("The altar falls into a chasm.");
goto do_pit;
#endif
#ifdef THRONES
case THRONE :
if (cansee(x,y))
pline("The throne falls into a chasm.");
/* Falls into next case */
#endif
case ROOM :
case CORR : /* Make a pit */
do_pit: chasm = maketrap(x,y,PIT);
chasm->tseen = 1;
levl[x][y].doormask = 0;
/* We have to check whether monsters or player
fall in a chasm... */
if (MON_AT(x, y)) {
mtmp = m_at(x,y);
if(!is_flyer(mtmp->data)) {
mtmp->mtrapped = 1;
if(cansee(x,y))
pline("%s falls into a chasm!",
Monnam(mtmp));
else if (flags.soundok && humanoid(mtmp->data))
You("hear a scream!");
if ((mtmp->mhp -= rnd(6)) <= 0) {
if(!cansee(x,y))
pline("It is destroyed!");
else {
You("destroy %s!",
mtmp->mtame ?
a2_monnam(mtmp, "poor") :
mon_nam(mtmp));
}
xkilled(mtmp,0);
}
}
} else if (x == u.ux && y == u.uy) {
if (Levitation
#ifdef POLYSELF
|| is_flyer(uasmon)
#endif
) {
pline("A chasm opens up under you!");
You("don't fall in!");
} else {
You("fall into a chasm!");
u.utrap = rn1(6,2);
u.utraptype = TT_PIT;
losehp(rnd(6),"fell into a chasm",
NO_KILLER_PREFIX);
selftouch("Falling, you");
}
} else
newsym(x,y);
break;
case DOOR : /* Make the door collapse */
if (levl[x][y].doormask == D_NODOOR) break;
if (cansee(x,y))
pline("The door collapses.");
levl[x][y].doormask = D_NODOOR;
mnewsym(x,y);
if (!MON_AT(x, y) && !(x == u.ux && y == u.uy))
newsym(x,y);
if (cansee(x,y)) prl(x,y);
break;
}
}
}
/*
* The player is trying to extract something from his/her instrument.
*/
static int
do_improvisation(instr)
struct obj *instr;
{
int damage;
if (Confusion)
pline("What you produce is quite far from music...");
else
You("start playing the %s.", xname(instr));
switch (instr->otyp) {
case FLUTE: /* May charm snakes */
if (rn2(ACURR(A_DEX)) + u.ulevel > 25)
charm_snakes((int)u.ulevel*3);
break;
case MAGIC_FLUTE: /* Make monster fall asleep */
if (instr->spe > 0) {
instr->spe--;
You("produce soft music.");
put_monsters_to_sleep((int)u.ulevel*5);
}
break;
case HORN: /* Awaken monsters or scare monsters */
You("produce a frightful, grave sound.");
awaken_monsters((int)u.ulevel*30);
break;
case FROST_HORN: /* Idem wand of cold */
case FIRE_HORN: /* Idem wand of fire */
if (instr->spe > 0) {
instr->spe--;
if (!getdir(1)) {
if (!Blind)
pline("The %s glows then fades.", xname(instr));
} else {
if (!u.dx && !u.dy && !u.dz) {
if((damage = zapyourself(instr)))
losehp(damage,
self_pronoun("using a magical horn on %sself", "him"),
NO_KILLER_PREFIX);
makeknown(instr->otyp);
return(2);
}
buzz((instr->otyp == FROST_HORN) ? 3 : 1, rn1(6,6), u.ux, u.uy, u.dx, u.dy);
makeknown(instr->otyp);
return(2);
}
}
break;
case BUGLE: /* Awaken & attract soldiers */
You("extract a loud noise from the %s.",xname(instr));
awaken_soldiers();
break;
case HARP: /* May calm Nymph */
if (rn2(ACURR(A_DEX)) + u.ulevel > 25)
calm_nymphs((int)u.ulevel*3);
break;
case MAGIC_HARP: /* Charm monsters */
if (instr->spe > 0) {
pline("The %s produces very attractive music.", xname(instr));
instr->spe--;
charm_monsters(((int)u.ulevel - 1) / 3 + 1);
}
break;
case DRUM: /* Awaken monsters */
You("beat a deafening row!");
awaken_monsters((int)u.ulevel * 40);
break;
case DRUM_OF_EARTHQUAKE: /* create several pits */
if (instr->spe > 0) {
You("produce a heavy, thunderous rolling!");
pline("The entire dungeon is shaking around you!");
instr->spe--;
do_earthquake(((int)u.ulevel - 1) / 3 + 1);
makeknown(DRUM_OF_EARTHQUAKE);
}
break;
default:
impossible("What a weird instrument (%d)!",instr->otyp);
break;
}
return (2); /* That takes time */
}
/*
* So you want music...
*/
int
do_play_instrument(instr)
struct obj *instr;
{
#ifdef STRONGHOLD
char buf[BUFSZ], *s, c = 'y';
int x,y;
boolean ok;
if (instr->otyp != DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
pline("Improvise? ");
c = yn();
}
if (c == 'n') {
pline("What tune are you playing? [what 5 notes] ");
getlin(buf);
for(s=buf;*s;s++)
if (islower(*s)) *s=toupper(*s);
You("extract a strange sound from the %s!",xname(instr));
/* Check if there was the Stronghold drawbridge near
* and if the tune conforms to what we're waiting for.
*/
if (dlevel == stronghold_level)
if (!strcmp(buf,tune)) {
/* Search for the drawbridge */
for(y=u.uy-1; y<=u.uy+1; y++)
for(x=u.ux-1;x<=u.ux+1;x++)
if(isok(x,y))
if (find_drawbridge(&x,&y)) {
if (levl[x][y].typ == DRAWBRIDGE_DOWN)
close_drawbridge(x,y);
else
open_drawbridge(x,y);
return 0;
}
} else if (flags.soundok) {
/* Okay, it wasn't the right tune, but perhaps
* we can give the player some hints like in the
* Mastermind game */
ok = FALSE;
for(y = u.uy-1; y <= u.uy+1 && !ok; y++)
for(x = u.ux-1; x <= u.ux+1 && !ok; x++)
if(isok(x,y))
if(IS_DRAWBRIDGE(levl[x][y].typ) ||
is_drawbridge_wall(x,y) >= 0)
ok = TRUE;
if (ok) { /* There is a drawbridge near */
int tumblers, gears;
boolean matched[5];
tumblers = gears = 0;
for(x=0; x < 5; x++)
matched[x] = FALSE;
for(x=0; x < strlen(buf); x++)
if(x < 5) {
if(buf[x] == tune[x]) {
gears++;
matched[x] = TRUE;
} else
for(y=0; y < 5; y++)
if(!matched[y] &&
buf[x] == tune[y] &&
buf[y] != tune[y]) {
tumblers++;
matched[y] = TRUE;
break;
}
}
if(tumblers)
if(gears)
You("hear %d tumbler%s click and %d gear%s turn.",
tumblers, plur((long)tumblers),
gears, plur((long)gears));
else
You("hear %d tumbler%s click.",
tumblers, plur((long)tumblers));
else if(gears)
You("hear %d gear%s turn.",
gears, plur((long)gears));
}
}
return 1;
} else
#endif /* STRONGHOLD /**/
return do_improvisation(instr);
}
#endif /* MUSIC /**/